﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using Microsoft.Practices.Composite.Presentation.Commands;

namespace Elentok.Common.Wpf.ViewModels.Dialogs
{
  /// <summary>
  /// This interface must be implemented in order to use the <see cref="Dialog"/> class.
  /// </summary>
  public interface IDialogViewModel : IViewModel
  {
    /// <summary>
    /// This event is raised when the view model is closed
    /// (the dialog should listen to this and close when this event is raised)
    /// </summary>
    event EventHandler<DialogClosedEventArgs> Closed;

    /// <summary>
    /// Gets the command that will be executed when the user 
    /// clicks the "Close" button of the window
    /// </summary>
    ICommand CancelCommand { get; }

    /// <summary>
    /// Returns true if the dialog view model is closed
    /// </summary>
    bool IsClosed { get; }

    /// <summary>
    /// This method is called when the dialog is first shown
    /// </summary>
    void OnShown();

    /// <summary>
    /// Gets the title of the dialog
    /// </summary>
    string Title { get; set; }
  }

  /// <summary>
  /// The base implementation of the <see cref="IDialogViewModel"/> interface
  /// </summary>
  public abstract class DialogViewModelBase : ViewModelBase, IDialogViewModel
  {
    private string title;
    private bool isClosed;

    /// <summary>
    /// Initializes an instance of the <see cref="DialogViewModelBase"/> class
    /// </summary>
    protected DialogViewModelBase()
    {
      this.CancelCommand = new DelegateCommand<object>(
        delegate { OnExecuteCancelCommand(); },
        delegate { return OnCanExecuteCancelCommand(); });
    }

    /// <summary>
    /// Raises the <see cref="Closed"/> event to notify the owning window
    /// that it needs to close
    /// </summary>
    protected void Close(bool result)
    {
      this.IsClosed = true;

      var handler = Closed;
      if (handler != null)
        handler(this, new DialogClosedEventArgs(result));
    }

    /// <summary>
    /// The execute method of the cancel command
    /// </summary>
    protected virtual void OnExecuteCancelCommand()
    {
      Close(false);
    }

    /// <summary>
    /// The can-execute method of the cancel command
    /// </summary>
    /// <returns></returns>
    protected virtual bool OnCanExecuteCancelCommand()
    {
      return true;
    }

    #region IDialogViewModel Members

    /// <summary>
    /// This event is raised when the view model is closed
    /// (the dialog should listen to this and close when this event is raised)
    /// </summary>
    public event EventHandler<DialogClosedEventArgs> Closed;

    /// <summary>
    /// Gets the command that will be executed when the user 
    /// clicks the "Close" button of the window
    /// </summary>
    public ICommand CancelCommand { get; private set; }

    /// <summary>
    /// Returns true if the dialog view model is closed
    /// </summary>
    public bool IsClosed
    {
      get
      {
        return this.isClosed;
      }
      private set
      {
        if (this.isClosed == value)
          return;

        OnPropertyChanging("IsClosed");
        this.isClosed = value;
        OnPropertyChanged("IsClosed");
      }
    }

    /// <summary>
    /// This method is called when the dialog is first shown
    /// </summary>
    public virtual void OnShown() { }
    
    /// <summary>
    /// Gets the title of the dialog
    /// </summary>
    public string Title
    {
      get
      {
        return this.title;
      }
      set
      {
        if (this.title == value)
          return;

        OnPropertyChanging("Title");
        this.title = value;
        OnPropertyChanged("Title");
      }
    }

    #endregion
  }

  /// <summary>
  /// The event args for the "Closed" event of the <see cref="IDialogViewModel"/>
  /// </summary>
  public class DialogClosedEventArgs : EventArgs
  {
    /// <summary>
    /// Gets the dialog result
    /// </summary>
    public bool Result { get; private set; }

    /// <summary>
    /// Initializes an instance of <see cref="DialogClosedEventArgs"/>
    /// </summary>
    /// <param name="result"></param>
    public DialogClosedEventArgs(bool result)
    {
      this.Result = result;
    }
  }
}
